package cc.rboot.abtest.aspect;

import cc.rboot.abtest.annotation.ABTest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@Aspect
@Component
public class ABTestAspect {

    @Pointcut("@annotation(cc.rboot.abtest.annotation.ABTest)")
    public void pointCut() {
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method targetMethod = methodSignature.getMethod();

        ABTest currentAbTest = targetMethod.getAnnotation(ABTest.class);

        String name = currentAbTest.name();
        int weightSum = 0;

        List<Method> abTestOfMethodList = new ArrayList<>();
        for (Method method : joinPoint.getTarget().getClass().getMethods()) {
            if (method.isAnnotationPresent(ABTest.class)) {
                ABTest abtest = method.getAnnotation(ABTest.class);
                if (name.equals(abtest.name())) {
                    weightSum = weightSum + abtest.weight();
                    abTestOfMethodList.add(method);
                }
            }
        }

        if (weightSum == 0) {
            return joinPoint.proceed();
        }
        int choice = new Random().nextInt(weightSum) + 1;
        // 累进游标
        int nonius = 0;
        for (Method method : abTestOfMethodList) {
            ABTest abtest = method.getAnnotation(ABTest.class);
            nonius = nonius + abtest.weight();
            if (nonius >= choice) {
                return method.invoke(joinPoint.getTarget(), joinPoint.getArgs());
            }
        }
        return joinPoint.proceed();
    }
}
